#include "head.h"



//class CdPlayer:public QWidget
//{
//    Q_OBJECT
//public:
//    CdPlayer();
//    ~CdPlayer();
//public:
//    constexpr static double pi = 3.1415926;
//private slots:
//    //参数是一个进度占比
//    void acceptMusicProgress(double rotia);
//    void acceptStart();
//signals:
//    //参数是一个进度占比
//    void musicProgress(double rotia);
//private:
//    void paintEvent(QPaintEvent *event) override;
//    void mousePressEvent(QMouseEvent *event) override;
//    void mouseMoveEvent(QMouseEvent *event) override;
//    void mouseReleaseEvent(QMouseEvent *event) override;
//private:
//    QPoint _centralPoint;//cd中心点
//    QPoint _centralRoundRadius;//圆半径
//    QPoint _cdArmPos;//cd的机器臂位置
//    QPoint _squareA;
//    QPoint _squareB;
//    QPoint _squareC;
//    QPoint _squareD;

//    double _orginalRotationAngle;
//    double _currentRotationAngle;
//    double _maxRotationAngle;
//};







CdPlayer::CdPlayer(QOpenGLWidget *parent)
    :QOpenGLWidget(parent)
{
    //设置最小值在使用布局管理器时很有必要。布局管理器的自动分配大小可能会是均匀分配
    setMinimumSize(Widget::MAINWIDGET_WIDTH, Height);
    resize(Widget::MAINWIDGET_WIDTH, Height);
//    QSurfaceFormat format;
//    format.setAlphaBufferSize(8); // 设置alpha缓冲区大小为8位
//    setFormat(format);

    setAttribute(Qt::WA_TranslucentBackground, true);
    setAttribute(Qt::WA_AlwaysStackOnTop);
    _picture = QImage(":/images/Resources/cdBackground.png");
    _picture2 = QImage(":/images/Resources/cdPlayJoystick.png");
//    _centralPoint = QPoint(width()/2, 426 - 25)
//    setStyleSheet("QLabel {background-color: white;}");//设置样式
//    setAutoFillBackground(true);//执行填充
}

void CdPlayer::initPoint(QPoint centralPoint, QPoint cdArmPos)
{
    _centralPoint = QPoint(width()/2, 326 - centralPoint.y());
    _cdArmPos = cdArmPos;
    _maxRotationAngle = 20;

    _isOrNoInRectArea = false;
    _centralRoundRadius = 325 - _centralPoint.x();
    _lengthA = 357.00;
    _lenthC = 318.00;
    _lenthB = 370.00;
    _lenthD = 302.00;

//    _curLengthA = _lengthA;
//    _curLenthB = _lenthB;
//    _curLenthC = _lenthC;
//    _curLenthD = _lenthD;

    _squareA = MyPoint(_cdArmPos.rx() - qSin(_angleAOrg) * _lengthA, _cdArmPos.y() + qCos(_angleAOrg)*_lengthA);
    _squareB = MyPoint(_cdArmPos.rx() - qSin(_angleBOrg) * _lenthB, _cdArmPos.y() + qCos(_angleBOrg)*_lenthB);
    _squareC = MyPoint(_cdArmPos.rx() - qSin(_angleCOrg) * _lenthC, _cdArmPos.y() + qCos(_angleCOrg)*_lenthC);
    _squareD = MyPoint(_cdArmPos.rx() - qSin(_angleDOrg) * _lenthD, _cdArmPos.y() + qCos(_angleDOrg)*_lenthD);

    _squareCurA = _squareA;
    _squareCurB = _squareB;
    _squareCurC = _squareC;
    _squareCurD = _squareD;

    _angleAMax = _maxRotationAngle*pi/180 + _angleAOrg;
    _angleBMax = _maxRotationAngle*pi/180 + _angleBOrg;
    _angleCMax = _maxRotationAngle*pi/180 + _angleCOrg;
    _angleDMax = _maxRotationAngle*pi/180 + _angleDOrg;

    _squareMaxA = MyPoint(_cdArmPos.rx() - qSin(_angleAMax) * _lengthA, _cdArmPos.y()
                          + qCos(_angleAMax)*_lengthA);

    _squareMaxB = MyPoint(_cdArmPos.rx() - qSin(_angleBMax) * _lenthB,
                          _cdArmPos.y() + qCos(_angleBMax)*_lenthB);

    _squareMaxC = MyPoint(_cdArmPos.rx() - qSin(_angleCMax) * _lenthC,
                          _cdArmPos.y() + qCos(_angleCMax)*_lenthC);

    _squareMaxD = MyPoint(_cdArmPos.rx() - qSin(_angleDMax) * _lenthD,
                          _cdArmPos.y() + qCos(_angleDMax)*_lenthD);


    _cdAngleMax = 360;
    _cdAngleMin = 0;
}


CdPlayer::~CdPlayer()
{
    glDeleteTextures(1, &_cdTex);
    glDeleteTextures(1, &_armTex);
}

void CdPlayer::acceptResetBegin()
{
    resetMin();
    update();
}

void CdPlayer::acceptStart()
{

}

void CdPlayer::acceptMusicProgress(double rotia)
{
    auto increase = rotia * _maxRotationAngle - _currentRotationAngle;
    auto radian = increase * pi/180;
    updateCurrentPoint(radian);
    update();
}

//检验是否在长方形内部
bool CdPlayer::locateSqureAreaInternal(QPoint p)
{
    auto PA = MyPoint(p) - _squareCurA;
    auto PB = MyPoint(p) - _squareCurB;
    auto PC = MyPoint(p) - _squareCurC;
    auto PD = MyPoint(p) - _squareCurD;

    auto PAPB = PA.x()*PB.y() - PA.y()*PB.x();
    auto PBPC = PB.x()*PC.y() - PB.y()*PC.x();
    auto PCPD = PC.x()*PD.y() - PC.y()*PD.x();
    auto PDPA = PD.x()*PA.y() - PD.y()*PA.x();

    if((PAPB > 0 && PBPC >0 && PCPD >0 && PDPA > 0) || (PAPB < 0 && PBPC < 0 && PCPD < 0 && PDPA < 0))
    {
        return  true;
    }else{
        return false;
    }


}


double getVecValue(const MyPoint &vec)
{
    return qSqrt((vec.x()*vec.x() + vec.y() * vec.y()));
}

//获取向量夹角，单位弧度
double CdPlayer::GetAngle(const QPoint &vec1, const QPoint & vec2)
{
    auto vec1Sqrt = qSqrt((vec1.x()*vec1.x() + vec1.y() * vec1.y()));
    auto vec2Sqrt = qSqrt((vec2.x()*vec2.x() + vec2.y() * vec2.y()));

    auto vec1vec2 = vec1.x()*vec2.x() + vec1.y()*vec2.y();

    auto cosValue = vec1vec2 / (vec1Sqrt * vec2Sqrt);

    auto diffRadian = qAcos(cosValue);

    return diffRadian;
}

double CdPlayer::GetAngle(const MyPoint &vec1, const MyPoint & vec2)
{
    auto vec1Sqrt = qSqrt((vec1.x()*vec1.x() + vec1.y() * vec1.y()));
    auto vec2Sqrt = qSqrt((vec2.x()*vec2.x() + vec2.y() * vec2.y()));

    auto vec1vec2 = vec1.x()*vec2.x() + vec1.y()*vec2.y();

    auto cosValue = vec1vec2 / (vec1Sqrt * vec2Sqrt);

    auto diffRadian = qAcos(cosValue);

    return diffRadian;
}


//出现bug第一时间先查看有没有不小心错漏的（比如应该写加号，结果是减号）
void CdPlayer::updateRadian()
{
    _squareCurA = MyPoint(_cdArmPos.rx() - qSin(_angleACur) * _lengthA, _cdArmPos.y() + qCos(_angleACur)*_lengthA);
    _squareCurB = MyPoint(_cdArmPos.rx() - qSin(_angleBCur) * _lenthB, _cdArmPos.y() + qCos(_angleBCur)*_lenthB);
    _squareCurC = MyPoint(_cdArmPos.rx() - qSin(_angleCCur) * _lenthC, _cdArmPos.y() + qCos(_angleCCur)*_lenthC);
    _squareCurD = MyPoint(_cdArmPos.rx() - qSin(_angleDCur) * _lenthD, _cdArmPos.y() + qCos(_angleDCur)*_lenthD);


}

void CdPlayer::updateCurrentPoint(double RadianAdded)
{
    _angleACur += RadianAdded;
    _angleBCur += RadianAdded;
    _angleCCur += RadianAdded;
    _angleDCur += RadianAdded;

    _currentRotationAngle += RadianAdded*180.0 / pi;

    _cdAngleCur = _currentRotationAngle/_maxRotationAngle * _cdAngleMax;
//    emit sendMusicProgress(_currentRotationAngle/_maxRotationAngle);
    updateRadian();

}
//叉乘
int CdPlayer::CrossProduct(const QPoint &vec1, const QPoint &vec2)
{
    return (vec1.x()*vec2.y() - vec1.y()*vec2.x());
}
//用于判断旋转方向，一个是当前鼠标坐标，一个是先前的鼠标坐标.正数是顺时针, 0是不动，负数是逆时针
int CdPlayer::AdvanceOrRetreat(const QPoint &dotCur, const QPoint &dot2Last)
{
    auto lastO = _cdArmPos - dot2Last;
    auto curO = dotCur - dot2Last;

    auto r = CrossProduct(lastO, curO);

    return r;
}


void CdPlayer::resetMin()
{
    _squareCurA = _squareA;
    _squareCurB = _squareB;
    _squareCurC = _squareC;
    _squareCurD = _squareD;

    _angleACur = _angleAOrg;
    _angleBCur = _angleBOrg;
    _angleCCur = _angleCOrg;
    _angleDCur = _angleDOrg;

    _currentRotationAngle = 0.00;
    _cdAngleCur = _cdAngleMin;
    emit sendMusicProgress(0);
    emit sendVlcProgress(0);
}

void CdPlayer::resetMax()
{
    _squareCurA = _squareMaxA;
    _squareCurB = _squareMaxB;
    _squareCurC = _squareMaxC;
    _squareCurD = _squareMaxD;

    _angleACur = _angleAMax;
    _angleBCur = _angleBMax;
    _angleCCur = _angleCMax;
    _angleDCur = _angleDMax;

    _currentRotationAngle = _maxRotationAngle;
    _cdAngleCur = _cdAngleMax;
    emit sendMusicProgress(1);
    emit sendVlcProgress(1);

}

//mousePress与mouseMove两者是独立的，不像dragEnterEvent和dropEvent
void CdPlayer::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        if(locateSqureAreaInternal(event->pos()))
        {
//            event->accept();
            _lastMousePos = event->pos();
            _isOrNoInRectArea = true;
        }else{
            _isOrNoInRectArea = false;
        }
    }
}



void CdPlayer::mouseMoveEvent(QMouseEvent *event)
{
    if((event->buttons() & Qt::LeftButton) && _isOrNoInRectArea)
    {

        auto diff1 = _lastMousePos - _cdArmPos;
        auto diff2 = event->pos() - _cdArmPos;

        auto radianAdded = GetAngle(diff1, diff2);
//        decltype (radianAdded) RadianAdded = 0;
        //向量叉乘判断旋转方向
        auto res = AdvanceOrRetreat(event->pos(), _lastMousePos);
//        qDebug() << radianAdded << "000";
        if(res < 0)
        {
            updateCurrentPoint(radianAdded);
//            RadianAdded = radianAdded;
        }else{
            updateCurrentPoint(-radianAdded);
//            RadianAdded = -radianAdded;
        }
        _lastMousePos = event->pos();
//        _currentMinDistance = qSin(GetAngle(_squareCurD - _squareCurA, MyPoint::ToMyPoint(_centralPoint) - _squareCurA))
//                * getVecValue(MyPoint::ToMyPoint(_centralPoint) - _squareCurA);
        if(/*_currentMinDistance < _centralRoundRadius*/ _currentRotationAngle >= _maxRotationAngle || _currentRotationAngle <= 0)
        {
            if(_currentRotationAngle <= 0)
            {
//                qDebug() << _currentRotationAngle*pi/180.0 << "000";

                resetMin();
                update();
            }else{

                resetMax();
                update();
            }
        }else{
            update();
        }
        {
            emit sendMusicProgress(_currentRotationAngle/_maxRotationAngle);
            emit sendVlcProgress(_currentRotationAngle/_maxRotationAngle);
        }
    }

}

void CdPlayer::errPrint(QString InforMation)
{
    decltype(glGetError()) err;
    err = glGetError();
    while (err != GL_NO_ERROR)
    {
        // auto string = gluErrorUnicodeStringEXT(GL_OUT_OF_MEMORY);
        // size_t lenU8 = WideCharToMultiByte(CP_ACP, 0, string, -1, nullptr, 0, nullptr, nullptr);
        // std::unique_ptr<char> u8str(new char[lenU8]());
        // WideCharToMultiByte(CP_ACP, 0, string, -1, u8str.get(), lenU8, nullptr, nullptr);
        qDebug()
            << "exit err! arr is " << err << InforMation;
        err = glGetError();
    }
}



void CdPlayer::mouseReleaseEvent(QMouseEvent *event)
{

}

void CdPlayer::paintGL()
{
    //未播放音乐前，如果频繁移动机械臂会导致图像消失，目前发现是下面两行代码的问题
//    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
//    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, width(), height(), 0, 0.1, 1000);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();



    CCVert cd[] ={
        {-211, -211, 0, 0, 1},
        {-211, 211, 0, 0,0},
        {211, 211, 0, 1, 0},
        {211, -211, 0, 1,1}
    };

    glTranslatef(_centralPoint.x(), _centralPoint.y(), -3);
    glRotatef(_cdAngleCur * 200, 0, 0, 1);



    glBindTexture(GL_TEXTURE_2D, _cdTex);

    glVertexPointer(3, GL_FLOAT, sizeof (CCVert), cd);
    glTexCoordPointer(2, GL_FLOAT, sizeof (CCVert), &cd[0].u);
    glDrawArrays(GL_QUADS, 0, 4);


    glLoadIdentity();
    CCVert arm[] = {
        {-123, -48, 0, 0, 0},
        {-123, 417 - 48, 0, 0,1},
        {211 - 123, 417 - 48, 0, 1, 1},
        {211 - 123, -48 , 0, 1,0}
    };
//    glTranslatef(0,0,-3);
    glTranslatef(_cdArmPos.x(), _cdArmPos.y(), -3);//指令逆序执行
    glRotatef(_currentRotationAngle, 0, 0, 1);


    glBindTexture(GL_TEXTURE_2D, _armTex);
    glVertexPointer(3, GL_FLOAT, sizeof (CCVert), arm);
    glTexCoordPointer(2, GL_FLOAT, sizeof (CCVert), &arm[0].u);
    glDrawArrays(GL_QUADS, 0, 4);

    errPrint("paintGL");

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}

void CdPlayer::initializeGL()
{
    initializeOpenGLFunctions();
    glClearColor(0,0,0,0);
    glClearDepth(1);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_TEXTURE_2D);

//    glEnable(GL_ALPHA_TEST);
//    glAlphaFunc(GL_GEQUAL, 1.0f);

    glEnable(GL_BLEND);//让图片背景透明，这个项目同等性能下启用混合比启用透明度测试，画质效果要好很多，gpu消耗略微上调一点。
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


    glGenTextures(1, &_cdTex);
    glBindTexture(GL_TEXTURE_2D, _cdTex);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _picture.width(), _picture.height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, _picture.bits());
    glGenTextures(1, &_armTex);
    glBindTexture(GL_TEXTURE_2D, _armTex);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _picture2.width(), _picture2.height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, _picture2.bits());


    glBindTexture(1, 0);
}
void CdPlayer::resizeGL(int w, int h)
{
    glViewport(0,0,w,h);
}



//void CdPlayer::paintEvent(QPaintEvent *event)
//{
//    Q_UNUSED(event)
//    QPainter paint(this);
//    paint.setRenderHints(QPainter::Antialiasing|QPainter::SmoothPixmapTransform, true);
//    paint.save();

//    QPixmap picture(":/images/Resources/cdBackground.png");
//    paint.translate(QPoint(_centralPoint));
//    paint.rotate(_cdAngleCur * 200);
//    paint.drawPixmap(QRect(-211,-211, 422, 422), picture, picture.rect());
//    paint.restore();

//    paint.save();
//    QPixmap picture2(":/images/Resources/cdPlayJoystick.png");
//    paint.translate(QPoint(_cdArmPos));
//    paint.rotate(_currentRotationAngle/*20*/);
// //    qDebug() << _currentRotationAngle << "paint";
//    paint.drawPixmap(QRect(-123,-48,211,417), picture2, picture2.rect());
//    paint.restore();
//}






